﻿namespace com.crownpack.ExportConfigurationDao
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;

    using com.crownpack.Extensions.SharePointExtensions;
    using com.crownpack.Extensions.StringExtensions;
    using com.crownpack.SharePoint;

    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Linq;

    using Context = ExportConfigurationDataContext;

    using ReferenceObject = ExportConfiguration;

    public class ExportConfigurationDao : BaseDao
    {
        #region Fields

        public const string ListName = "exportconfiguration";

        #endregion Fields

        #region Constructors

        public ExportConfigurationDao( )
            : base(ListName)
        {
            CurrentWebUrl = SPContext.Current.Site.RootWeb.Url;
        }

        public ExportConfigurationDao( string currentWebUrl )
            : base(ListName)
        {
            CurrentWebUrl = currentWebUrl;
        }

        #endregion Constructors

        #region Methods

        public static List<InvolvedSite> GetSitesWithExportConfigurationDefined( string sitecollectionurl )
        {
            List<InvolvedSite> sites = new List<InvolvedSite>( );
            using ( SPSite spSite = new SPSite( sitecollectionurl ) )
            {
                sites = spSite.RootWeb.GetSubwebsForCurrentUser( ).Where( w => w.Lists.ContainsList( ListName ) ).Select( w =>
                {
                    SPList spList = w.Lists.GetListByRootFolder( ListName );
                    return new InvolvedSite
                    {
                        ListID = spList == null ? Guid.Empty : spList.ID,
                        ListTitle = spList == null ? string.Empty : spList.Title,
                        SiteTitle = w.Title,
                        SiteUrl = w.Url
                    };
                } ).ToList( );
            }
            return sites;
        }

        public static InvolvedSite GetSiteWithExportConfigurationDefined( string sitecollectionurl )
        {
            using ( SPSite spSite = new SPSite( sitecollectionurl ) )
            {
                bool ok = spSite.RootWeb.Lists.ContainsList( ListName );
                if ( ok )
                {
                    SPList spList = spSite.RootWeb.Lists.GetListByRootFolder( ListName );
                    return new InvolvedSite
                    {
                        ListID = spList == null ? Guid.Empty : spList.ID,
                        ListTitle = spList == null ? string.Empty : spList.Title,
                        SiteTitle = spSite.RootWeb.Title,
                        SiteUrl = spSite.RootWeb.Url
                    };
                }
                else
                    return null;
            }
        }

        public ReferenceObject Add( ReferenceObject value )
        {
            using ( Context c = new Context( CurrentWebUrl ) )
            {
                EntityList<ReferenceObject> l = c.GetList<ReferenceObject>( ListTitle );
                ReferenceObject v = clean( value );
                string title = v.Title;
                Guid g = Guid.NewGuid( );
                v.Title = g.ToString( );
                l.InsertOnSubmit( v );
                c.SubmitChanges( );
                v = ( from o in l
                      where o.Title == g.ToString( )
                      select o ).SingleOrDefault( );
                v.Title = title;
                c.SubmitChanges( );
                return resolveObject( v );
            }
        }

        public void Delete( int id )
        {
            using ( Context c = new Context( CurrentWebUrl ) )
            {
                EntityList<ReferenceObject> l = c.GetList<ReferenceObject>( ListTitle );
                var v = ( from o in l
                          where o.Id == id
                          select o );
                if ( v.Count( ) > 0 )
                {
                    l.DeleteAllOnSubmit( v );
                    c.SubmitChanges( );
                }
            }
        }

        public void Delete( Guid uniqueId )
        {
            using ( Context c = new Context( CurrentWebUrl ) )
            {
                EntityList<ReferenceObject> l = c.GetList<ReferenceObject>( ListTitle );
                var v = ( from o in l
                          where o.UniqueId == uniqueId
                          select o );
                if ( v.Count( ) > 0 )
                {
                    l.DeleteAllOnSubmit( v );
                    c.SubmitChanges( );
                }
            }
        }

        public ReferenceObject Get( int id )
        {
            using ( Context c = new Context( CurrentWebUrl ) )
            {
                EntityList<ReferenceObject> l = c.GetList<ReferenceObject>( ListTitle );
                ReferenceObject v = ( from o in l
                                      where o.Id.HasValue && o.Id.Value == id
                                      select o ).SingleOrDefault( );
                return resolveObject( v );
            }
        }

        public ReferenceObject Get( Guid id )
        {
            using ( Context c = new Context( CurrentWebUrl ) )
            {
                EntityList<ReferenceObject> l = c.GetList<ReferenceObject>( ListTitle );
                ReferenceObject v = ( from o in l
                                      where o.UniqueId == id
                                      select o ).SingleOrDefault( );
                return resolveObject( v );
            }
        }

        public List<ReferenceObject> GetActiveFullExport( )
        {
            using ( Context c = new Context( CurrentWebUrl ) )
            {
                EntityList<ReferenceObject> l = c.GetList<ReferenceObject>( ListTitle );
                List<ReferenceObject> v = ( from o in l
                                            where
                                            o.Active.Value &&
                                            o.ExportType.HasValue &&
                                            o.ExportType.Value == ExportType.Full
                                            select o ).DefaultIfEmpty( ).ToList( );
                if ( v.Count == 1 && v[ 0 ] == null )
                    v.Clear( );
                v.ForEach( a => resolveObject( a ) );
                return v;
            }
        }

        public List<ReferenceObject> GetActiveIncrementalExport( )
        {
            using ( Context c = new Context( CurrentWebUrl ) )
            {
                EntityList<ReferenceObject> l = c.GetList<ReferenceObject>( ListTitle );
                List<ReferenceObject> v = ( from o in l
                                            where
                                            o.Active.Value &&
                                            o.ExportType.HasValue &&
                                            o.ExportType.Value == ExportType.Incremental
                                            select o ).DefaultIfEmpty( ).ToList( );
                if ( v.Count == 1 && v[ 0 ] == null )
                    v.Clear( );
                v.ForEach( a => resolveObject( a ) );
                return v;
            }
        }

        public List<ReferenceObject> GetAll( )
        {
            using ( Context c = new Context( CurrentWebUrl ) )
            {
                List<ReferenceObject> l = c.GetList<ReferenceObject>( ListTitle ).ToList( );
                l.ForEach( a => resolveObject( a ) );
                return l;
            }
        }

        public void Update( ReferenceObject value )
        {
            using ( Context c = new Context( CurrentWebUrl ) )
            {
                EntityList<ReferenceObject> l = c.GetList<ReferenceObject>( ListTitle );
                ReferenceObject v = ( from p in l
                                      where p.UniqueId.Equals( value.UniqueId )
                                      select p ).SingleOrDefault( );
                if ( v != null )
                {
                    v.LastExport = value.LastExport;
                    v.ResetLastExport = false;
                    c.SubmitChanges( );
                }
            }
        }

        ReferenceObject clean( ReferenceObject value )
        {
            return new ReferenceObject
            {
                Active = value.Active,
                DocumentLibrary = value.DocumentLibrary,
                DocumentName = value.DocumentName,
                ExportType = value.ExportType,
                Header = value.Header,
                IncludeAuthor = value.IncludeAuthor,
                IncludeContentType = value.IncludeContentType,
                IncludeCreated = value.IncludeCreated,
                IncludeEditor = value.IncludeEditor,
                IncludeItemUrl = value.IncludeItemUrl,
                IncludeModified = value.IncludeModified,
                IncludeUniqueId = value.IncludeUniqueId,
                LastExport = value.LastExport,
                List = value.List,
                ResetLastExport = value.ResetLastExport,
                Title = value.Title
            };
        }

        string resolveDocumentName( string documentName )
        {
            const string DATE = "$date$";
            const string TIME = "$time$";
            const char defaultChar = '_';
            DateTime currentDate = DateTime.Now;
            string date = currentDate.ToString( "yyyy-MM-dd" );
            string time = currentDate.ToString( "HH.mm.ss" );
            string s = documentName.ToLower( );
            s = s.Replace( DATE, date ).Replace( TIME, time );
            if ( !s.IsFileNameLegal( ) )
            {
                char[ ] invalidFileNameChars = Path.GetInvalidFileNameChars( );
                foreach ( char c in invalidFileNameChars )
                    s = s.Replace( c, defaultChar );
            }
            return s;
        }

        ReferenceObject resolveObject( ReferenceObject value )
        {
            value.DocumentLibraryUrl = resolveUrl( value.DocumentLibraryUrl );
            value.DocumentName = resolveDocumentName( value.DocumentName );
            return value;
        }

        string resolveUrl( string url )
        {
            Uri currentWeb = new Uri( CurrentWebUrl );
            Uri uri = new Uri( url );
            UriBuilder ub = new UriBuilder( );
            ub.Host = currentWeb.Host;
            ub.Scheme = currentWeb.Scheme;
            if ( currentWeb.Port > 0 )
                ub.Port = currentWeb.Port;
            ub.Path = uri.LocalPath;
            string s = ub.ToString( );
            ub = null;
            return s;
        }

        #endregion Methods
    }
}